package com.ryan.mdp.connection;

import java.io.IOException;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.jms.ConnectionFactory;
import javax.naming.NamingException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.jndi.JndiTemplate;

import com.ryan.mdp.exception.MdpError;

/**
 * Jms ConnectionFactory工具类，简化ConnectionFactory的配置. <br/>
 * jms ConnectionFactory可以通过以下三种方式获取：
 * <ol>
 * <li>通过spring注入properties属性指定jms连接信息；</li>
 * <li>如果上面方法失败，可以通过java System Enviroment变量"jms.properties"注入jms连接信息。</li>
 * </ol>
 * 提供第二种方式的原因是以防万一哪天NFS失效，可以通过环境变量临时指定JMS资源的目录位置
 * 
 * @author botao.liao
 * 
 */
public class JndiConnectionFactoryUtil {

    private static final Logger logger = LoggerFactory.getLogger(JndiConnectionFactoryUtil.class);

    // 通过环境变量来找到JMS连接信息
    private static final String ENV_JMS_RESOURCE = "JMS_PROPERTIES";
    private static final String FACTORY = "java.naming.factory.initial";
    private static final String URL = "java.naming.provider.url";
    private static final String PRINCIPAL = "java.naming.security.principal";
    private static final String CREDENTIALS = "java.naming.security.credentials";
    private static final String CONNECTION_FACTORY_JNDINAME = "connection.factory.jndiname";

    public static ConnectionFactory getConnectionFactory(String prefix, String properties) {
        // 通过JNDI获取ConnectionFactory
        String envProperties = System.getenv(ENV_JMS_RESOURCE);
        if (properties == null && envProperties == null) {
            throw new MdpError("01020001");
        }
        String factory = null;
        String url = null;
        String principal = null;
        String credentials = null;
        String jndiname = null;

        Properties props = null;
        props = loadJmsResource(prefix, properties);
        if (props == null && envProperties != null) {
            props = loadJmsResource(prefix, envProperties);
        }
        prefix = prefix == null ? "" : prefix.trim() + ".";
        factory = props.getProperty(prefix + FACTORY);
        url = props.getProperty(prefix + URL);
        principal = props.getProperty(prefix + PRINCIPAL);
        credentials = props.getProperty(prefix + CREDENTIALS);
        jndiname = props.getProperty(prefix + CONNECTION_FACTORY_JNDINAME);

        try {
            Properties env = new Properties();
            env.setProperty(FACTORY, factory);
            env.setProperty(URL, url);
            env.setProperty(PRINCIPAL, principal);
            env.setProperty(CREDENTIALS, credentials);
            JndiTemplate jndiTemplate = new JndiTemplate(env);
            ConnectionFactory connFactory = (ConnectionFactory) jndiTemplate.lookup(jndiname, ConnectionFactory.class);
            return connFactory;
        } catch (NamingException e) {
            throw new MdpError("01020010", e, jndiname);
        }
    }

    /**
     * 读取jms resource
     * 
     * @param prefix
     * @param properties
     * @return
     * @throws MdpError
     */
    private static Properties loadJmsResource(String prefix, String properties) throws MdpError {
        if (properties == null) {
            return null;
        }
        Properties props = null;
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        StringTokenizer tokenizer = new StringTokenizer(properties, ",");
        while (tokenizer.hasMoreTokens()) {
            String propfile = tokenizer.nextToken();
            logger.info("loading jms resource from {}", propfile);
            Resource resource = resourceLoader.getResource(propfile);
            if (resource.exists()) {
                try {
                    props = PropertiesLoaderUtils.loadProperties(resource);
                } catch (IOException e) {
                    throw new MdpError("01020003", e);
                }
                String factory = props.getProperty((prefix == null ? "" : prefix.trim() + ".") + FACTORY);
                if (factory == null) {
                    logger.info("not found matched jms resource in {} started with prefix {}", propfile, prefix);
                } else {
                    break;
                }
            } else {
                logger.info("not found jms resource {}", propfile);
            }
        }
        return props;
    }
}
